/**
 * 
 */
package com.williamoneil.charts.client.widget;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.Context2d.TextBaseline;
import com.williamoneil.charts.client.data.ChartBoundsRect;
import com.williamoneil.charts.client.data.ChartElementsData;
import com.williamoneil.charts.client.data.DateAxis;
import com.williamoneil.charts.client.data.HorizontalGridLine;
import com.williamoneil.charts.client.data.PriceAxis;
import com.williamoneil.charts.client.data.VerticalGridLine;
import com.williamoneil.charts.client.util.ChartUtil;
import com.williamoneil.charts.client.util.ColorEntityType;
import com.williamoneil.charts.client.util.Colors;

/**
 * @author gudipati
 *
 */
public class GridLinesLayer extends ChartOverlay {

	public GridLinesLayer(ChartBoundsRect chartBounds) {
		super(chartBounds);
	}
	
	/* (non-Javadoc)
	 * @see com.williamoneil.charts.client.widget.ChartOverlay#drawOverlay()
	 */
	@Override
	public void drawOverlay() {
		this.drawChartBounds();
		this.drawGridLines();
	}
	
	public void drawChartBounds() {
		if(super.getChartBoundsRect() == null) {
			return;
		}
		final int x = super.getChartBoundsRect().getX();
		final int y = super.getChartBoundsRect().getY();
		
		final Context2d context = super.getGraphicsContext();
		
		context.setFillStyle(Colors.getColorTheme().getColor(ColorEntityType.CHART_BACKGROUND));
		context.setLineWidth(1);
		
		// first draw the chart outer bounds first
		context.beginPath();
		context.fillRect(0, 0, super.getChartBoundsRect().getTotalWidth(), super.getChartBoundsRect().getTotalHeight());
		context.fill();
		
		context.setStrokeStyle(Colors.getColorTheme().getColor(ColorEntityType.CHART_BORDER));
		ChartUtil.roundedRect(context, x, y, super.getChartBoundsRect().getWidthWithScale(), super.getChartBoundsRect().getHeightWithScale(), 5);
		
		context.beginPath();
		// next draw the line bordering the x-scale labels  
		ChartUtil.lineTo(context, x, super.getChartBoundsRect().getHeightWithoutScale(), super.getChartBoundsRect().getWidthWithScale(), super.getChartBoundsRect().getHeightWithoutScale());
		context.stroke();
		
		//GWT.log("ChartBounds: " + super.getChartBoundsRect().toString());
		//GWT.log("Canvas Size: oh=" + super.getCanvas().getOffsetHeight() + ";ow=" + super.getCanvas().getOffsetWidth() + "; csh=" + super.getCanvas().getCoordinateSpaceHeight() + "; ccsw=" + super.getCanvas().getCoordinateSpaceWidth());
	}
	
	public void drawGridLines() {
		final ChartElementsData elements = super.getChartElements();
		if(elements == null) {
			return;
		}
		
		final List<HorizontalGridLine> horizontalGridLines = elements.getHorizontalGridLines();
		final List<VerticalGridLine> verticalGridLines = elements.getVerticalGridLines();
		if(verticalGridLines == null || horizontalGridLines == null) {
			return;
		}

		final Context2d context = super.getGraphicsContext();
		
		context.setStrokeStyle(Colors.getColorTheme().getColor(ColorEntityType.MINOR_GRIDLINE));
		context.setLineWidth(0.5);

		final List<VerticalGridLine> vGridLinesWithLabels = new ArrayList<VerticalGridLine>();
		final List<HorizontalGridLine> hGridLinesWithLabels = new ArrayList<HorizontalGridLine>();

		// Draw all grid lines together
		context.beginPath();
		for(final VerticalGridLine aGL : verticalGridLines) {
			drawVerticalGridLine(context, aGL);
			
			if(aGL.isMajor()) {
				vGridLinesWithLabels.add(aGL);
			}
		}
		for(final HorizontalGridLine aGL : horizontalGridLines) {
			drawHorizontalGridLine(context, aGL);
			
			if(aGL.isMajor()) {
				hGridLinesWithLabels.add(aGL);
			}
		}
		context.stroke();
			
		context.setFont("10pt Calibri");
		context.setTextBaseline(TextBaseline.HANGING);
		context.setFillStyle(Colors.getColorTheme().getColor(ColorEntityType.GRIDLINE_LABEL));
		for(final VerticalGridLine aGL : vGridLinesWithLabels) {
			drawVerticalGridLineLabel(context, aGL);
		}
		for(final HorizontalGridLine aGL : hGridLinesWithLabels) {
			drawHorizontalGridLineLabel(context, aGL);
		}
		context.stroke();
	}
	
	private void drawVerticalGridLine(Context2d context, VerticalGridLine aGL) {
		final DateAxis dateAxis = super.getChartElements().getDateAxis();
		final int x = dateAxis.getX(aGL.getValue());
		
		if(x < super.getChartBoundsRect().getX() 
				|| x > super.getChartBoundsRect().getWidthWithoutScale()) {
			return;
		}
		
		if(aGL.isMajor()) {
			ChartUtil.lineTo(context, x, super.getChartBoundsRect().getY(), x, super.getChartBoundsRect().getHeightWithoutScale());
		} else {
			ChartUtil.dashLineTo(context, x, super.getChartBoundsRect().getY(), x, super.getChartBoundsRect().getHeightWithoutScale(), 2, 2);
		}
	}
	
	private void drawVerticalGridLineLabel(Context2d context, VerticalGridLine aGL) {
		final DateAxis dateAxis = super.getChartElements().getDateAxis();
		final int x = dateAxis.getX(aGL.getValue());
		
		if(x < super.getChartBoundsRect().getX() || x > super.getChartBoundsRect().getWidthWithoutScale()) {
			return;
		}

		context.fillText(aGL.getValueAsText(), x, super.getChartBoundsRect().getHeightWithoutScale());
	}
	
	private void drawHorizontalGridLine(Context2d context, HorizontalGridLine aGL) {
		final PriceAxis priceAxis = super.getChartElements().getPriceAxis();
		final int y = priceAxis.getY(aGL.getValue(), super.getChartBoundsRect());
		
		if(y < super.getChartBoundsRect().getY() || y > super.getChartBoundsRect().getHeightWithoutScale()) {
			return;
		}
			
		if(aGL.isMajor()) {
			ChartUtil.lineTo(context, super.getChartBoundsRect().getX(), y, super.getChartBoundsRect().getWidthWithoutScale(), y);
		} else {
			ChartUtil.dashLineTo(context, super.getChartBoundsRect().getX(), y, super.getChartBoundsRect().getWidthWithoutScale(), y, 2, 2);
		}
	}
	
	private void drawHorizontalGridLineLabel(Context2d context, HorizontalGridLine aGL) {
		final PriceAxis priceAxis = super.getChartElements().getPriceAxis();
		final int y = priceAxis.getY(aGL.getValue(), super.getChartBoundsRect());
		
		if(y < super.getChartBoundsRect().getY() || y > super.getChartBoundsRect().getHeightWithoutScale()) {
			return;
		}
		
		context.fillText(aGL.getValueAsText(), super.getChartBoundsRect().getWidthWithoutScale(), y);
	}
}
